package com.dongbao.core.rules.java;

import com.dongbao.core.base.CodeRulesCommonBase;
import com.dongbao.core.rules.CodeRulesBase;
import com.dongbao.entity.AwardedInfo;
import com.intellij.lang.jvm.JvmParameter;
import com.intellij.lang.jvm.annotation.JvmAnnotationAttribute;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.PsiClassImpl;
import com.intellij.psi.impl.source.tree.java.PsiLiteralExpressionImpl;
import com.intellij.psi.impl.source.tree.java.PsiNameValuePairImpl;

import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 *  数据库表名及字段命名符合小驼峰命名，达到名字即注释的效果
 * */
public class DataBaseTableNameRules extends CodeRulesCommonBase implements CodeRulesBase {

    private final List<String> BASE_MODEL_NAMES = Arrays.asList("BaseModel","HoldBaseModel","HoldBaseOrgExtModel","HoldBaseOrgModel","HoldOrgModel","HoldOrgSortModel");

    private final List<String> specialChar = Arrays.asList("!","~","`","@","#","$","%","^","&","*","(",")","-","=","+","/","\\",".",",");

    public DataBaseTableNameRules(VirtualFile afterFile,PsiFile psiFile,Project project) {
        super(afterFile,psiFile,project);
        this.code = "A008";
        this.level = "A";
    }

    /**
     * 执行规则判断
     * */
    @Override
    public void run(List<AwardedInfo> deduction) {
        /* 执行分析当前class是否负责当前规则 */
        PsiAnnotation[] annotations = psiClassImpls.get(0).getModifierList().getAnnotations();
        for(PsiClassImpl psiClass:psiClassImpls){
            /* 判断是否是 po 类 如果集成的类名是:BaseModel、HoldBaseModel、HoldBaseOrgExtModel、HoldBaseOrgModel、HoldOrgModel、HoldOrgSortModel 则是实体 */
            PsiElement[] children = psiClass.getExtendsList().getChildren();
            if(children==null || children.length==0){
                continue;
            }
            List<PsiElement> collect = Arrays.stream(children).filter(node -> {
                return BASE_MODEL_NAMES.contains(node.getText());
            }).collect(Collectors.toList());
            if(collect.isEmpty()){
                /* 没有继承符合条件的基类,所以判断不做规则验证,下一位 */
                continue;
            }
            /* 获取类上方的注解,是否有 @TableName("") 的注解,如果判断是PO但是没有这个注解则提示 */
            PsiAnnotation[] allAnno = psiClass.getAnnotations();
            PsiAnnotation tableNameAnno = Arrays.stream(allAnno).filter(anno -> {
                return "com.baomidou.mybatisplus.annotation.TableName".equals(anno.getQualifiedName());
            }).findAny().orElse(null);

            /* 获取错误代码行位置 */
            Document document = PsiDocumentManager.getInstance(psiClass.getProject()).getDocument(psiClass.getContainingFile());
            int lineNumber = document.getLineNumber(tableNameAnno.getTextOffset());

            if(tableNameAnno == null){

                /* 作为PO没有使用 @TableName 注解,进行提示*/
                packDeduction(
                        deduction,
                        psiClass.getName(),
                        psiPackageStatements.get(0).getPackageName(),
                        null,
                        "PO实体类缺少@TableName注解,无法对数据表命名做出规则审计,请补充PO中@TableName",lineNumber,lineNumber);
                continue;
            }
            /* 判断  @TableName("") 值是否符合命名要求 */
            if(tableNameAnno.getAttributes().isEmpty()){

                packDeduction(
                        deduction,
                        psiClass.getName(),
                        psiPackageStatements.get(0).getPackageName(),
                        null,
                        "PO实体类缺少@TableName注解中缺少value对表名的说明",lineNumber,lineNumber);
                continue;
            }
            JvmAnnotationAttribute value = tableNameAnno.getAttributes().stream().filter(item -> {
                return item.getAttributeName().equals("value");
            }).findAny().orElse(null);
            if(value==null){

                packDeduction(
                        deduction,
                        psiClass.getName(),
                        psiPackageStatements.get(0).getPackageName(),
                        null,
                        "PO实体类缺少@TableName注解中缺少value对表名的说明",lineNumber,lineNumber);
                continue;
            }
            String attValue = ((PsiNameValuePairImpl)value).getValue().getText().replace("\"","");
            /* 判断是否存在特殊字符 */
            List<String> eligibilitySpecial = specialChar.stream().filter(special -> {
                return attValue.contains(special);
            }).collect(Collectors.toList());
            if(!eligibilitySpecial.isEmpty()){

                packDeduction(
                        deduction,
                        psiClass.getName(),
                        psiPackageStatements.get(0).getPackageName(),
                        null,
                        String.format("PO实体类缺少@TableName注解中的表名存在特殊字符,请检查表名是否按照规范创建"),lineNumber,lineNumber);
                continue;
            }
            /* 判断是否存在大写字符 */
            int funNUmber = fun(attValue);
            if(funNUmber>0){

                packDeduction(
                        deduction,
                        psiClass.getName(),
                        psiPackageStatements.get(0).getPackageName(),
                        null,
                        String.format("PO实体类缺少@TableName注解中的表名存在大写字符,请检查是是否按照规范创建"),lineNumber,lineNumber);
                continue;
            }
            /* 判断是否存在数字 */
            if(HasDigit(attValue)){
                packDeduction(
                        deduction,
                        psiClass.getName(),
                        psiPackageStatements.get(0).getPackageName(),
                        null,
                        String.format("PO实体类缺少@TableName注解中的表名存在数字,请检查是是否按照规范创建"),lineNumber,lineNumber);
                continue;
            }
        }
    }

    public boolean HasDigit(String content) {
        boolean flag = false;
        Pattern p = Pattern.compile(".*\\d+.*");
        Matcher m = p.matcher(content);
        if (m.matches()) {
            flag = true;
        }
        return flag;
    }

    public static int fun(String str){
        char[] c=str.toCharArray();
        int daxie=0;
        for(int i=0;i<str.length();i++){
            if(c[i]>='A'&&c[i]<='Z'){
                daxie++;
            }
        }
        return daxie;
    }

    @Override
    public String describe() {
        return "命名规则";
    }


//    public class User {
//        private String name;
//        private String password;
//        private String address;
//        private String phone;
//        private String remark;
//        public User(String name, String password, String address, String phone, String remark) {
//            this.name = name;
//            this.password = password;
//            this.address = address;
//            this.phone = phone;
//            this.remark = remark;
//            除了赋值操作外还有其他代码的则会进行提示
//            System.out.println("666");
//        }
//    }


}
